package com.winit.common.sg;

import com.alibaba.fastjson.JSONObject;
import com.winit.common.sg.JavaDocReader;
import com.winit.common.sg.JavaParserUtil;
import org.springframework.core.io.support.PropertiesLoaderUtils;
import org.springframework.util.StringUtils;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.*;

/**
 * Created by wanglin on 2018/5/9.
 */
public class AnalysisUtil {

    private static String spiPath;
    static {
        try {
            Properties properties = PropertiesLoaderUtils.loadAllProperties("application.properties");
            spiPath = properties.getProperty("spi_path");
        } catch (Exception e) {
        }

    }


    public static JSONObject analysis(String dubboUrl) throws Exception {
        JSONObject rtnObj = new JSONObject();
        //方法路径
        String servicePath = RegularUtil.getServicePath(dubboUrl, "$5")+RegularUtil.FILESUFFIX;
        //接口名
        String serviceName = RegularUtil.getServiceName(servicePath, "$3");
        //所属系统
        String serviceSys = RegularUtil.getServicePathSys(servicePath, "$3");
        //组service对象
        JSONObject serviceObject=new JSONObject();
        serviceObject.put("path",servicePath);
        serviceObject.put("name",serviceName);
        serviceObject.put("sys",serviceSys);
        String remarks = JavaDocReader.fileComments(spiPath + servicePath);
        if(!StringUtils.isEmpty(remarks)){
            serviceObject.put("remarks",remarks);
        }
        rtnObj.put("service",serviceObject);
        //解析文件
        List<JSONObject> list = getParseMethodDefs(spiPath + servicePath);
        if(list!=null){
            rtnObj.put("method",list);
            List<JSONObject> models = new ArrayList<>();
            for(JSONObject li:list){
                List methodParamArr = (List) li.get("param");
                JSONObject rtn = (JSONObject) li.get("rtn");
                if(methodParamArr==null){
                    continue;
                }
                for(int i=0;i<methodParamArr.size();i++){
                    JSONObject methodParam =(JSONObject) methodParamArr.get(i);
                    if(!StringUtils.isEmpty(methodParam.getString("path")) && new File(spiPath+methodParam.getString("path")).exists()){
                        models=getModel(methodParam.getString("type"),methodParam.getString("path"),methodParam.getString("name"),methodParam.getString("isBase"),models,3);
                    }
                }
                if(null != rtn){
                    models=getModel(rtn.getString("contain")!=null ? rtn.getString("contain") : rtn.getString("type"),rtn.getString("path"),rtn.getString("contain")!=null ? rtn.getString("contain") : rtn.getString("type"),"0",models,0);
                }
            }
            rtnObj.put("models",models);
        }

        System.out.println(rtnObj);
        return rtnObj;
    }


    private static List<JSONObject> getModel(String type, String path,String name, String isBase, List<JSONObject> models,int count) throws IOException {
        if(new File(spiPath+path).exists()){
            JSONObject model = new JSONObject();
            model.put("type",type);
            model.put("path",path);
            model.put("name",name);
            if(!StringUtils.isEmpty(isBase) && "1".equals(isBase)){
                model.put("isbase","1");
            }else{
                model.put("isbase","0");
                //判断是否是项目文件
                JSONObject parameter = getParameter(type, path);
                model.put("params",parameter.getJSONArray("params"));
                model.put("extends",parameter.getString("extends"));
                model.put("remarks",parameter.getString("remarks"));
                List<JSONObject> customs =(List) parameter.getJSONArray("customs");
                if(count!=0){
                    count--;
                    if(customs.size()!=0){
                        for(JSONObject cust:customs){
                            getModel(cust.getString("type"),cust.getString("path"),cust.getString("name"),null,models,count);
                        }
                    }
                }
            }
            models.add(model);
        }
        return models;
    }

        private static List<JSONObject> getParseMethodDefs(String path) throws IOException {
            File file = new File(path);
            if (!file.exists()) {
                System.out.println("文件不存在！！！！path:" + path);
                return null;
            }

            List<JSONObject> remarks = JavaDocReader.method(path);
            List<JSONObject> list = new ArrayList<>();
            List<JSONObject> methodDefs = new JavaParserUtil().parseMethodDefs(path);
            if(methodDefs!=null){
                for(JSONObject methodDef:methodDefs){
                    JSONObject map = new JSONObject();
                    map.put("name",methodDef.getString("name"));
                    for(JSONObject rm:remarks){
                        if(methodDef.getString("name").equals(rm.getString("name"))){
                            map.put("remarks",rm.getString("remarks"));
                            break;
                        }
                    }
                    List<JSONObject> param =getEntity((List) methodDef.getJSONArray("params"),path);
                    map.put("param",param.size()>0 ? param : null);
                    String rtnName = methodDef.getString("rtn");
                    if("void".equals(rtnName)){
                        map.put("rtn",null);
                    }else{
                        Map<String, Object> rtn = isBasicType(rtnName,path);
                        JSONObject rtnObject = new JSONObject();
                        if("0".equals(rtn.get("code"))){
                            rtnObject.put("type",rtn.get("type"));
                        }else if("2".equals(rtn.get("code"))){
                            rtnObject.put("type",rtn.get("type"));
                            rtnObject.put("contain",rtn.get("contain"));
                            rtnObject.put("path",getEntityPath(path, (String) rtn.get("contain")) + RegularUtil.FILESUFFIX);
                        }else if("3".equals(rtn.get("code"))){
                            rtnObject.put("type",rtn.get("type"));
                            String entity = methodDef.getString("rtnExtends");
                            String entityPath = null;
                            if (entity.contains(".")) {
                                entityPath = entity.replace(".", "/") + RegularUtil.FILESUFFIX;
                            } else {
                                try {
                                    entityPath = getEntityPath(path, entity) + RegularUtil.FILESUFFIX;
                                } catch (IOException e) {
                                    System.out.println("文件打开异常:"+e.getMessage());
                                    e.printStackTrace();
                                }
                            }
                            rtnObject.put("extends",entityPath);
                        }else{
                            String entityPath;
                            if (rtnName.contains(".")) {
                                entityPath = rtnName.replace(".", "/") + RegularUtil.FILESUFFIX;
                            } else {
                                entityPath = getEntityPath(path, rtnName) + RegularUtil.FILESUFFIX;
                            }
                            rtnObject.put("type",rtnName);
                            rtnObject.put("path",entityPath);
                        }
                        map.put("rtn",rtnObject );
                    }
                    list.add(map);
                }
            }
            return list;
        }

    //获取参数方法
    private static List<JSONObject> getEntity(List<JSONObject> parameterList, String path) throws IOException {

        List<JSONObject> arrayList = new ArrayList<>();
        for (JSONObject parameter : parameterList) {
            JSONObject jsonObject=new JSONObject();

            String name = parameter.getString("name");
            String type = parameter.getString("type");
            jsonObject.put("name",name);
            Map<String, Object> map = isBasicType(type,path);
            if("0".equals(map.get("code"))){
                jsonObject.put("type",map.get("type"));
                jsonObject.put("isbase","1");
                jsonObject.put("path",null);
            }else if("2".equals(map.get("code"))){
                jsonObject.put("type",map.get("type"));
                jsonObject.put("path",null);
                jsonObject.put("isbase","1");
                jsonObject.put("contain",map.get("contain"));
            }else{
                jsonObject.put("type",type);
                String entityPath;
                if (type.contains(".")) {
                    entityPath = type.replace(".", "/") + RegularUtil.FILESUFFIX;
                } else {
                    entityPath = getEntityPath(path, type) + RegularUtil.FILESUFFIX;
                }
                jsonObject.put("path",entityPath);
            }
            arrayList.add(jsonObject);
        }
        return arrayList;
    }

    /**
     * 验证传入参数是否是基本类型
     * 返回code 0基础类型
     *         1为自定义类型
     *         2为Map,List,Set等基本类型存在泛型
     *         3为<T extends xxx> T 类型
     *         -1为异常
     * @param parameter
     * @return
     */
    private static Map<String, Object> isBasicType(String parameter,String path) throws IOException {
        Map<String, Object> map = new HashMap<>();
        if(!StringUtils.isEmpty(parameter)){
            if (parameter.contains("List<")) {
                map.put("code","2");
                map.put("type","List");
                map.put("contain",RegularUtil.getListEntity(parameter, "$3"));
            } else if(parameter.contains("Map<")){
                map.put("code","2");
                map.put("type","Map");
                map.put("contain",RegularUtil.getListEntity(parameter, "$3").split(","));
            }else if(parameter.contains("Page<")){
                map.put("code","2");
                map.put("type","Page");
                map.put("contain",RegularUtil.getListEntity(parameter, "$3"));

            }else if(parameter.contains("Set<")){
                map.put("code","2");
                map.put("type","Set");
                map.put("contain",RegularUtil.getListEntity(parameter, "$3"));
            }else if(parameter.contains("GetByKeyCommand<")){
                map.put("code","2");
                map.put("type","GetByKeyCommand");
                map.put("contain",RegularUtil.getListEntity(parameter, "$3"));
            }
            else if(parameter.equals("T")){
                map.put("code","3");
                map.put("type", "T");
            }else{
                boolean isTrue=true;
                for(String str:RegularUtil.BasicTypes){
                    if(parameter.equals(str) && isTrue){
                        map.put("code","0");
                        map.put("type",str);
                        isTrue=false;
                    }
                }
                if(isTrue){
                    map.put("code","1");
                }
            }

        }else{
            map.put("code","-1");
        }
        return map;
    }


    private static JSONObject getParameter(String entity, String entityPath) throws IOException {
        JSONObject model = new JSONObject();
        Set<JSONObject> set = new HashSet();
        if (!"SPICommand".equals(entity) && !entity.contains("<")) {
            set = JavaParserUtil.getParameter(spiPath + entityPath, set);
        }
        if(set.size()>0){
            JSONObject remarks = JavaDocReader.fields(spiPath+entityPath);
            String fileRemark = remarks.getString("fileRemark");
            if(!StringUtils.isEmpty(fileRemark)){
                model.put("remarks",fileRemark);
            }
            List<JSONObject> rmList = (List)remarks.getJSONArray("rmList");
            List<JSONObject> params = new ArrayList<>();
            List<JSONObject> customs=new ArrayList<>();
            for(JSONObject s:set){
                JSONObject param = new JSONObject();
                String type = s.getString("type");
                for(JSONObject remark:rmList){
                    if(s.getString("name").equals(remark.getString("name"))){
                        param.put("remarks",remark.getString("remarks"));
                    }
                }
                Map<String, Object> basicType = isBasicType(type, entityPath);
                if("0".equals(basicType.get("code"))){
                    param.put("type",basicType.get("type"));
                    param.put("name",s.getString("name"));
                }else if("1".equals(basicType.get("code"))){
                    param.put("type",type);
                    param.put("name",s.getString("name"));
                    String path;
                    if (s.getString("name").contains(".")) {
                        path = s.getString("name").replace(".", "/") + RegularUtil.FILESUFFIX;
                    } else {
                        path = getEntityPath(spiPath+entityPath, s.getString("type")) + RegularUtil.FILESUFFIX;
                    }
                    param.put("path",path);
                    customs.add(param);

                }else if("2".equals(basicType.get("code"))){
                    param.put("contain",basicType.get("contain"));
                    param.put("type",basicType.get("type"));
                }
                params.add(param);
            }
            //实体中内中的自定义实体
            model.put("customs",customs);
            model.put("params",params);
            String extend = getExtend(spiPath + entityPath);
            model.put("extends",StringUtils.isEmpty(extend) ? null : extend);
        }
        return model;
    }

    //获取实体路径
    private static String getEntityPath(String path, String entity) throws IOException {
        File file = new File(path);
        String entityPath = "";
        if (file.exists()) {
            FileReader reader = new FileReader(file);
            BufferedReader bReader = new BufferedReader(reader);
            String s;
            //逐行读取文件内容，不读取换行符和末尾的空格
            Boolean isAll = false;
            Boolean isTrue = false;
            while ((s = bReader.readLine()) != null) {
                if (!StringUtils.isEmpty(RegularUtil.getEntityPath(entity, s, "$3"))) {
                    entityPath = RegularUtil.getEntityPath(entity, s, "$3");
                    isTrue = true;
                    break;
                }
                if (s.matches(RegularUtil.isPathAll) && !isAll) {
                    entityPath = s.replaceAll(RegularUtil.getPathAll, "$4") + entity;
                    entityPath = entityPath.replace(".", "/");
                    File newFile = new File(spiPath + entityPath + RegularUtil.FILESUFFIX);
                    if (newFile.exists()) {
                        isAll = true;
                        isTrue = true;
                    }
                }
            }
            if (!isTrue) {
                entityPath = RegularUtil.getUpPath(file.getPath(), "$3") + "/" + entity;
            }
        }
        return entityPath;
    }

    //获取继承实体名
    private static String getExtend(String path) throws IOException {
        if(path==null){
            return null;
        }
        File file = new File(path);
        if(!file.exists()){
            System.out.println("文件不存在！");
            return null;
        }
        FileReader reader = new FileReader(file);
        //new一个BufferedReader对象，将文件内容读取到缓存
        BufferedReader bReader = new BufferedReader(reader);
        //定义一个字符串缓存，将字符串存放缓存中
        String s;
        //逐行读取文件内容，不读取换行符和末尾的空格
        String entity = "";
        Boolean isTrue = false;
        while ((s = bReader.readLine()) != null && !isTrue) {
            entity = RegularUtil.getExtend(s, "$6");
            if (!StringUtils.isEmpty(entity)) {
                isTrue = true;
            }
        }
        if(entity==null){
            return null;
        }
        String fatherPath;
        fatherPath = getEntityPath(path, entity) + RegularUtil.FILESUFFIX;
        bReader.close();
        return fatherPath;
    }


    public static void main(String[] args) throws Exception {
//        getParameter("Searchable","com/winit/common/query/Searchable.java");

//        getExtend("/Users/wanglin/JavaProject/spi/src/main/java/com/winit/oms/spi/common/vo/PageVo.java");
        analysis("/dubbo/com.winit.cwm.spi.delivery.DeliveryOrderService/providers/dubbo%3A%2F%2F10.32.31.137%3A20817%2Fcom.winit.cwm.spi.delivery.DeliveryOrderService%3Fanyhost%3Dtrue%26application%3Dcwm%26default.cluster%3Dfailover%26default.executes%3D500%26default.loadbalance%3Drandom%26default.retries%3D0%26default.timeout%3D60000%26default.validation%3Dtrue%26dispatcher%3Dall%26dubbo%3D2.9.0-SNAPSHOT%26dynamic%3Dfalse%26generic%3Dfalse%26group%3DBEMO.CWM.UK.EUR%26interface%3Dcom.winit.cwm.spi.delivery.DeliveryOrderService%26methods%3DupdateDeliveryOrder%2CqueryDeliveryOrders%2CcompleteWorkOrder%2CqueryDeliveryOrderByWorkOrderNo%2CprintDeliveryOrder%2CupdateDeliveryOrderState%26organization%3Dwinit%26owner%3Dbin.zi%26pid%3D25112%26revision%3D1.0.0%26side%3Dprovider%26threadpool%3Dlimited%26threads%3D200%26timestamp%3D1502797668737%26version%3D1.0.0");
    }


}
